package com.lambert.ginkgo.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List; /**
 * Message comprising the conversation.
 *
 * @param rawContent The contents of the message. The message content is always a
 * {@link String}.
 * @param role The role of the messages author. Could be one of the {@link Role}
 * types.
 * @param name An optional name for the participant. Provides the model information to
 * differentiate between participants of the same role. In case of Function calling,
 * the name is the function name that the message is responding to.
 * @param toolCallId Tool call that this message is responding to. Only applicable for
 * the {@link Role#TOOL} role and null otherwise.
 * @param toolCalls The tool calls generated by the model, such as function calls.
 * Applicable only for {@link Role#ASSISTANT} role and null otherwise.
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public record ChatCompletionMessage(// @formatter:off
                                    @JsonProperty("content") Object rawContent,
                                    @JsonProperty("role") Role role,
                                    @JsonProperty("name") String name,
                                    @JsonProperty("tool_call_id") String toolCallId,
                                    @JsonProperty("tool_calls")
                                    @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) List<ToolCall> toolCalls,
                                    @JsonProperty("prefix") Boolean prefix,
                                    @JsonProperty("reasoning_content") String reasoningContent) { // @formatter:on

    /**
     * Create a chat completion message with the given content and role. All other
     * fields are null.
     * @param content The contents of the message.
     * @param role The role of the author of this message.
     */
    public ChatCompletionMessage(Object content, Role role) {
        this(content, role, null, null, null, null, null);
    }

    /**
     * Create a chat completion message with the given content and role. All other
     * fields are null.
     * @param content The contents of the message.
     * @param role The role of the author of this message.
     * @param name The name of the author of this message.
     * @param toolCallId The id of the tool call.
     * @param toolCalls The tool calls generated by the model, such as function calls.
     */
    public ChatCompletionMessage(Object content, Role role, String name, String toolCallId,
                                 List<ToolCall> toolCalls) {
        this(content, role, name, toolCallId, toolCalls, null, null);
    }

    /**
     * Get message content as String.
     */
    public String content() {
        if (this.rawContent == null) {
            return null;
        }
        if (this.rawContent instanceof String text) {
            return text;
        }
        throw new IllegalStateException("The content is not a string!");
    }

    /**
     * The role of the author of this message.
     */
    public enum Role {

        /**
         * System message.
         */
        @JsonProperty("system")
        SYSTEM,
        /**
         * User message.
         */
        @JsonProperty("user")
        USER,
        /**
         * Assistant message.
         */
        @JsonProperty("assistant")
        ASSISTANT,
        /**
         * Tool message.
         */
        @JsonProperty("tool")
        TOOL

    }

    /**
     * The relevant tool call.
     *
     * @param index The index of the tool call in the list of tool calls. Required in
     * case of streaming.
     * @param id The ID of the tool call. This ID must be referenced when you submit
     * the tool outputs in using the Submit tool outputs to run endpoint.
     * @param type The type of tool call the output is required for. For now, this is
     * always function.
     * @param function The function definition.
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public record ToolCall(// @formatter:off
                           @JsonProperty("index") Integer index,
                           @JsonProperty("id") String id,
                           @JsonProperty("type") String type,
                           @JsonProperty("function") ChatCompletionFunction function) { // @formatter:on

        public ToolCall(String id, String type, ChatCompletionFunction function) {
            this(null, id, type, function);
        }

    }

    /**
     * The function definition.
     *
     * @param name The name of the function.
     * @param arguments The arguments that the model expects you to pass to the
     * function.
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public record ChatCompletionFunction(// @formatter:off
                                         @JsonProperty("name") String name,
                                         @JsonProperty("arguments") String arguments) { // @formatter:on
    }
}
